package com.teamclub.base.sservices.storage
import java.io.IOException
import java.nio.file.{Files, Path, Paths}
import java.util.function.Predicate
import java.util.stream.{Stream => JStream}

import com.sun.org.apache.xml.internal.utils.URI.MalformedURIException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.io.{Resource, UrlResource}
import org.springframework.stereotype.Service
import org.springframework.util.FileSystemUtils
import org.springframework.web.multipart.MultipartFile

/**
  * Created by ilkkzm on 17-6-23.
  */
@Service
class FileSystemStorgeService() extends StorageService {

  var rootLocation: Path = _

  @Autowired
  def this(props: StorageProperties) = {
    this()
    rootLocation = Paths.get(props.getLocation)
    if(!rootLocation.toFile.exists()){
      init()
    }
  }

  override def init() = {
    try {
      Files.createDirectory(rootLocation)
    } catch {
      case e: IOException => {
        throw new StorageException("Could not init storage", e)
      }
    }
  }



  override def store(file: MultipartFile) = {
    try {
      if(file.isEmpty) {
        throw new StorageException(s"Failed to store empty file ${file.getOriginalFilename}")
      }
      Files.copy(file.getInputStream, this.rootLocation.resolve(file.getOriginalFilename))
    } catch {
      case e: IOException => {
        throw new StorageException(s"Failed to store file ${file.getOriginalFilename}", e)
      }
    } finally {
      if(file != null && file.getInputStream != null) { file.getInputStream.close() }
    }
  }

  override def loadAll(): JStream[Path] = {
    try {
      return Files.walk(rootLocation, 1).filter(new Predicate[Path] {
        override def test(t: Path): Boolean = !t.equals(rootLocation)
      }).map(new java.util.function.Function[Path, Path] {
        override def apply(t: Path): Path = {
          rootLocation.relativize(t)
        }
      })
    } catch {
      case e: IOException => {
        throw new StorageException("Failed to read stored files", e)
      }
    }
  }


  override def load(filename: String): Path = {
    return rootLocation.resolve(filename)
  }

  override def loadAsResource(filename: String): Resource = {
    try {
      val file = load(filename)
      val resource = new UrlResource(file.toUri)
      if(resource.exists || resource.isReadable) {
        return resource
      } else {
        throw new StorageFileNotFoundException("Cound not read file: " + filename)
      }
    } catch {
      case e: MalformedURIException => {
        throw new StorageFileNotFoundException("Could not read file: " + filename, e)
      }
    }
  }

  override def deleteAll(): Unit = {
    FileSystemUtils.deleteRecursively(rootLocation.toFile)
  }
}
